package frame.laxcen.util;

import frame.laxcen.BaseFrame;
import util.ByteUtil;

import java.util.function.Consumer;

// 四种读模式 每种每次完整读出一个参数的数据 每种读模式支持 U8 U16 U32 三种位长

// readUx    => | Data:   Ux  |
// readUxs   => | Length: U16 | Data: Array[Ux] |
// readPx    => | PID:    U8  | Data: Ux        |
// readPxs   => | PID:    U8  | Length: U16     | Data: Array[Ux] |

// 辅助的读写模式

// readU8n   => | Data: Array[U8] | 无条件读取n个U8

public class FrameReader {

    private int position;

    private final byte[] frameData;

    public FrameReader(byte[] frame) {

        this.position = 0;

        this.frameData = frame;
    }

    public FrameReader(BaseFrame frame) {

        this(frame.FrameData);
    }

    public boolean hasNext() {

        return position < frameData.length;
    }

    public byte readU8() {

        return frameData[position++];
    }

    public byte[] readU8s() {

        byte[] buffer = new byte[ByteUtil.bytePairToInt(readU8(), readU8())];

        for(int i = 0; i < buffer.length; ++i) buffer[i] = readU8();

        return buffer;
    }

    public short readU16() {

        return ByteUtil.bytePairToShort(readU8(), readU8());
    }

    public short[] readU16s() {

        short[] buffer = new short[ByteUtil.bytePairToInt(readU8(), readU8())];

        for(int i = 0; i < buffer.length; ++i) buffer[i] = readU16();

        return buffer;
    }

    public int readU32() {

        return ByteUtil.bytePairToInt(readU8(), readU8(), readU8(), readU8());
    }

    public int[] readU32s() {

        int[] buffer = new int[ByteUtil.bytePairToInt(readU8(), readU8())];

        for(int i = 0; i < buffer.length; ++i) buffer[i] = readU16();

        return buffer;
    }

    public boolean readPid(byte pid) {

        return hasNext() && Byte.compare(pid, frameData[position]) == 0 && (position += 1) > -1;
    }

    public Byte readP8(byte pid) {

        return readPid(pid) ? readU8() : null;
    }

    public void readP8(byte pid, Consumer<Byte> consumer) {

        if(readPid(pid)) consumer.accept(readU8());
    }

    public byte[] readP8s(byte pid) {

        return readPid(pid) ? readU8s() : null;
    }

    public void readP8s(byte pid, Consumer<byte[]> consumer) {

        if(readPid(pid)) consumer.accept(readU8s());
    }

    public Short readP16(byte pid) {

        return readPid(pid) ? readU16() : null;
    }

    public void readP16(byte pid, Consumer<Short> consumer) {

        if(readPid(pid)) consumer.accept(readU16());
    }

    public short[] readP16s(byte pid) {

        return readPid(pid) ? readU16s() : null;
    }

    public void readP16s(byte pid, Consumer<short[]> consumer) {

        if(readPid(pid)) consumer.accept(readU16s());
    }

    public Integer readP32(byte pid) {

        return readPid(pid) ? readU32() : null;
    }

    public void readP32(byte pid, Consumer<Integer> consumer) {

        if(readPid(pid)) consumer.accept(readU32());
    }

    public int[] readP32s(byte pid) {

        return readPid(pid) ? readU32s() : null;
    }

    public void readP32s(byte pid, Consumer<int[]> consumer) {

        if(readPid(pid)) consumer.accept(readU32s());
    }

    public byte[] readU8n(int length) {

        byte[] buffer = new byte[length];

        for(int i = 0; i < buffer.length; ++i) buffer[i] = readU8();

        return buffer;
    }
}
